import re
from functools import wraps

from flask import session, request, redirect, url_for

from model.crud import QueryOneInstance
from model.tables import User
from restful.error import RenderUserNotAdmin, RenderUserNotExist
from restful.response import ResponseBadRequest


def add_session(uid):
    session['uid'] = uid

def del_session():
    session.clear()

#TODO
def query_session():
    return True

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not query_session():
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_function

def current_user_required(f):
    @wraps(f)
    @login_required
    def decorated_function(*args, **kwargs):
        user = QueryOneInstance(User, {'id': session['uid']})
        if not user:
            return RenderUserNotExist(session['uid'])
        kwargs['current_user'] = user
        return f(*args, **kwargs)
    return decorated_function


def current_user_is_admin_required(f):
    @wraps(f)
    @current_user_required
    def decorated_function(*args, **kwargs):
        if not kwargs['current_user'].admin:
            return RenderUserNotAdmin(kwargs['current_user'].id)
        return f(*args, **kwargs)
    return decorated_function

def data(field_defs: dict):
    def str_to_bool(value):
        if isinstance(value, str):
            if value.lower() in ('true', '1', 'yes'):
                return True
            elif value.lower() in ('false', '0', 'no'):
                return False
        return bool(value)

    def decorator(func):
        @wraps(func)
        def wrapper(*f_args, **f_kwargs):
            # get 从params中拿
            # 其他从json或form中拿
            if request.method == 'GET':
                source = request.args
            else:
                source = request.json if request.is_json else request.form

            data = {}

            for name, rules in field_defs.items():
                required = rules.get('required', False)
                expected_type = rules.get('type', str)
                regex = rules.get('regex')
                help_text = rules.get('help')

                value = source.get(name)

                if required and (value is None or value == ''):
                    return ResponseBadRequest(f"{name} 字段不存在")

                if value is not None:
                    try:
                        if expected_type is bool:
                            value = str_to_bool(value)
                        else:
                            value = expected_type(value)
                    except (ValueError, TypeError):
                        return ResponseBadRequest(f"{name} 字段类型必须是 {expected_type.__name__}")

                    if regex and not re.fullmatch(regex, str(value)):
                        return ResponseBadRequest(help_text or f"{name} 字段格式不正确")
                data[name] = value
            return func(*f_args, data=data, **f_kwargs)
        return wrapper
    return decorator